package com.jwsoft.manager.core.integration.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bifang.engine.assistant.core.annotation.ApiService;
import com.bifang.engine.assistant.core.annotation.OpApi;
import com.bifang.engine.assistant.core.annotation.SaveOplog;
import com.bifang.engine.assistant.core.enums.AuTypeEnum;
import com.bifang.engine.assistant.core.enums.FuncTypeEnum;
import com.bifang.engine.data.core.util.PagerUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jwsoft.manager.common.constant.EduCache;
import com.jwsoft.manager.common.enums.EduDataTaskTypeEnum;
import com.jwsoft.manager.common.enums.EduStatusTypeEnum;
import com.jwsoft.manager.common.vo.eduDataTaskDetail.DataTaskDetailOptionVO;
import com.jwsoft.manager.core.dao.model.EduDataTask;
import com.jwsoft.manager.core.dao.service.EduDataTaskService;
import com.jwsoft.manager.core.dao.service.TableService;
import com.jwsoft.manager.core.dao.service.impl.TableServiceFactory;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import cn.hutool.core.convert.Convert;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import com.bifang.engine.assistant.core.exception.AppException;
import org.springframework.util.ObjectUtils;
import org.springframework.transaction.annotation.Transactional;
import com.bifang.engine.assistant.core.enums.BoolEnum;
import com.jwsoft.manager.common.vo.eduDataTaskDetail.EduDataTaskDetailVO;
import com.jwsoft.manager.common.vo.eduDataTaskDetail.EduDataTaskDetailKeyVO;
import com.jwsoft.manager.common.vo.eduDataTaskDetail.EduDataTaskDetailQueryVO;
import com.jwsoft.manager.core.integration.EduDataTaskDetailIntegration;
import com.jwsoft.manager.core.dao.service.EduDataTaskDetailService;
import com.jwsoft.manager.core.dao.model.EduDataTaskDetail;
/**
 * 数据备份任务详情表业务实现类
 *
 * @author zhiyuan
 * @since 2023-09-13
 */
@ApiService(funcCode = "eduDataTaskDetail", title = "数据备份任务详情表")
@Slf4j
public class EduDataTaskDetailIntegrationImpl implements EduDataTaskDetailIntegration {

    @Autowired
    private EduDataTaskDetailService eduDataTaskDetailService;

    @Autowired
    private EduDataTaskService eduDataTaskService;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    @OpApi(funcCode = "eduDataTaskDetail0001", title = "数据备份任务详情表分页查询", funcType = FuncTypeEnum.query)
    public PageInfo<EduDataTaskDetailVO> getList(EduDataTaskDetailQueryVO vo) {
        // 开启分页
        if (vo.getPageNum() == null || vo.getPageSize() == null) {
            //如果不传入分页参数，默认最大取1000条
            vo.setPageNum(1);
            vo.setPageSize(1000);
        }
        PageHelper.startPage(vo.getPageNum(),vo.getPageSize());
        List<EduDataTaskDetail> list = eduDataTaskDetailService.list();
        if (CollectionUtils.isEmpty(list)) {
            // 判断是否为空，为空则返回空参数
            return PagerUtil.createEmptyPagerInfo(vo.getPageNum(), vo.getPageSize());
        }
        // 不为空则获取分页结果
        PageInfo<EduDataTaskDetail> pageInfo = new PageInfo<>(list);
        // 返回参数需要通过common层的vo实体类，用该方法可以批量转换
        List<EduDataTaskDetailVO> resultList = Convert.toList(EduDataTaskDetailVO.class, pageInfo.getList());
        // 转义数据字典值
        // dictHelper.valueToName(resultList, Arrays.asList(DemoDictEnum.values()));
        return PagerUtil.parsePagerVo(resultList, pageInfo);
    }

    @Override
    @OpApi(funcCode = "eduDataTaskDetail0002", title = "数据备份任务详情表根据主键查询详情", funcType = FuncTypeEnum.query)
    public EduDataTaskDetailVO getById(EduDataTaskDetailKeyVO vo) {
        EduDataTaskDetail entity = eduDataTaskDetailService.getById(vo.getTaskDetailId());
        if (ObjectUtils.isEmpty(entity)) {
            throw new AppException("查询不到详细信息!");
        }
        return Convert.convert(EduDataTaskDetailVO.class, entity);
    }
    /** 保存前统一校验*/
    @Override
    @OpApi(funcCode = "eduDataTaskDetail0003", title = "数据备份任务详情表保存前校验", funcType = FuncTypeEnum.other ,checkPrivilege = BoolEnum.FALSE)
    public void checkSave(EduDataTaskDetailVO vo) {
        //主键为空为新增校验

        //主键不为空为修改校验
    }

    @Override
    @OpApi(funcCode = "eduDataTaskDetail0004", title = "数据备份任务详情表新增", funcType = FuncTypeEnum.insert)
    @SaveOplog(
            operationType = "eduDataTaskDetail0004",
            operationName = "数据备份任务详情表新增",
            dataType = "taskDetailId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public EduDataTaskDetailVO add(EduDataTaskDetailVO vo) {
        //保存前校验
        checkSave(vo);
        //保存数据
        EduDataTaskDetail entity = Convert.convert(EduDataTaskDetail.class, vo);
        eduDataTaskDetailService.save(entity);
        //将主键设置回vo使操作日志可以取到
        vo.setTaskDetailId(entity.getTaskDetailId());
        return vo;
    }

    @Override
    @OpApi(funcCode = "eduDataTaskDetail0005", title = "数据备份任务详情表修改", funcType = FuncTypeEnum.update)
    @SaveOplog(
            operationType = "eduDataTaskDetail0005",
            operationName = "数据备份任务详情表修改",
            dataType = "taskDetailId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public EduDataTaskDetailVO edit(EduDataTaskDetailVO vo) {
        if (ObjectUtils.isEmpty(vo.getTaskDetailId())) {
            throw new AppException("传入需要修改的主键不能为空!");
        }
        EduDataTaskDetail oldEntity = eduDataTaskDetailService.getById(vo.getTaskDetailId());
        if (ObjectUtils.isEmpty(oldEntity)) {
            throw new AppException("查询不到需要修改的信息!");
        }
        //保存前校验
        checkSave(vo);
        //保存数据
        EduDataTaskDetail entity = Convert.convert(EduDataTaskDetail.class, vo);
        eduDataTaskDetailService.updateById(entity);
        return vo;
    }

    @Override
    @OpApi(funcCode = "eduDataTaskDetail0006", title = "数据备份任务详情表根据主键删除", funcType = FuncTypeEnum.delete)
    @SaveOplog(
            operationType = "eduDataTaskDetail0006",
            operationName = "数据备份任务详情表删除",
            dataType = "taskDetailId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public void del(EduDataTaskDetailKeyVO vo) {
        if (ObjectUtils.isEmpty(vo.getTaskDetailId())) {
            throw new AppException("传入需要删除的数据主键不能为空!");
        }
        EduDataTaskDetail entity = eduDataTaskDetailService.getById(vo.getTaskDetailId());
        if (ObjectUtils.isEmpty(entity)) {
            throw new AppException("未找到需要删除的信息!");
        }
        eduDataTaskDetailService.removeById(vo.getTaskDetailId());
    }

    @Override
    @OpApi(funcCode = "eduDataTaskDetail0007", title = "单业务数据迁移", funcType = FuncTypeEnum.update)
    public void dataTaskMigration(EduDataTaskDetailQueryVO vo) {
        if (ObjectUtils.isEmpty(vo.getYear())){
            throw new AppException("年份不能为空！");
        }
        if (ObjectUtils.isEmpty(vo.getTaskDetailId())){
            throw new AppException("任务详情id不能为空");
        }
        EduDataTaskDetail taskDetail = eduDataTaskDetailService.getById(vo.getTaskDetailId());
        if (ObjectUtils.isEmpty(taskDetail)) {
            throw new AppException("查询不到详细信息!");
        }
        RLock lock =
                redissonClient.getLock(EduCache.EDU_DATA_TASK_DETAIL + vo.getTaskDetailId());
        try {
            boolean lockAcquired = lock.tryLock(1000, 200000, TimeUnit.MILLISECONDS); // 尝试获取锁
            if (lockAcquired) {
                String handleTable = taskDetail.getHandleTable();
                if (ObjectUtils.isEmpty(handleTable)){
                    throw new AppException("任务配置的表名为空，请联系检查数据:"+taskDetail.getTaskDetailId());
                }
                //校验迁移是否执行过
                if (EduStatusTypeEnum.success.getType().equalsIgnoreCase(taskDetail.getMigrationStatus())){
                    throw new AppException("当前"+handleTable+"表迁移已完成，无需再次进行迁移");
                }
                TableService tableService = TableServiceFactory.getTableService(handleTable);
                DataTaskDetailOptionVO optionVO = new DataTaskDetailOptionVO();
                optionVO.setYear(vo.getYear());
                optionVO.setTaskDetailId(vo.getTaskDetailId());
                Integer migrationCount = null;
                try {
                    migrationCount = tableService.dataMigration(optionVO);
                }catch (AppException e){
                    throw new AppException(e.getMessage());
                }catch (Exception e) {
                    throw new Exception(e.getMessage());
                }
                //迁移成功
                taskDetail.setMigrationStatus(EduStatusTypeEnum.success.getType());
                taskDetail.setMigrationRemarks("迁移成功！");
                taskDetail.setMigrationTime(new Date());
                if (migrationCount != 0){
                    taskDetail.setMigrationCount(migrationCount);
                }
                eduDataTaskDetailService.updateById(taskDetail);
                //检查迁移任务是否已全部执行完毕
                this.checkMigrationTask(taskDetail.getTaskId());
            } else {
                // 未获取到锁，表示已经有其他请求在处理
                throw new AppException(taskDetail.getHandleTable() +"正在进行数据迁移，请稍后再试");
            }
        }catch (AppException e){
            log.error(e.getMessage());
            throw new AppException(e.getMessage());
        }catch (Exception e) {
            //发生异常，再去查询一遍任务，如果迁移状态未成功，就去处理
            EduDataTaskDetail newTaskDetail = eduDataTaskDetailService.getById(vo.getTaskDetailId());
            if (!EduStatusTypeEnum.success.getType().equalsIgnoreCase(newTaskDetail.getMigrationStatus())){
                //迁移失败
                taskDetail.setMigrationStatus(EduStatusTypeEnum.error.getType());
                String errorMessage = e.getMessage();
                if (errorMessage.length() > 500) {
                    errorMessage = errorMessage.substring(0, 500); // 截断到指定长度
                }
                taskDetail.setMigrationRemarks(errorMessage);
                taskDetail.setMigrationTime(new Date());
                eduDataTaskDetailService.updateById(taskDetail);
            }
            throw new RuntimeException(e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    @OpApi(funcCode = "eduDataTaskDetail0008", title = "单业务数据加密", funcType = FuncTypeEnum.update)
    public void dataTaskDetailEncrypt(EduDataTaskDetailQueryVO vo) {
        if (ObjectUtils.isEmpty(vo.getYear())){
            throw new AppException("年份不能为空！");
        }
        if (ObjectUtils.isEmpty(vo.getTaskDetailId())){
            throw new AppException("任务详情id不能为空");
        }
        EduDataTaskDetail taskDetail = eduDataTaskDetailService.getById(vo.getTaskDetailId());
        if (ObjectUtils.isEmpty(taskDetail)) {
            throw new AppException("查询不到详细信息!");
        }
        RLock lock = redissonClient.getLock(EduCache.EDU_DATA_TASK_DETAIL + vo.getTaskDetailId());
        try {
            boolean lockAcquired = lock.tryLock(1000, 200000, TimeUnit.MILLISECONDS); // 尝试获取锁
            if (lockAcquired) {
                String handleTable = taskDetail.getHandleTable();
                if (ObjectUtils.isEmpty(handleTable)){
                    throw new AppException("任务配置的表名为空，请联系检查数据:"+taskDetail.getTaskDetailId());
                }
                //校验当前任务是否完成数据迁移
                if (!EduStatusTypeEnum.success.getType().equalsIgnoreCase(taskDetail.getMigrationStatus())){
                    throw new AppException(handleTable+"未完成数据迁移，请进行数据迁移后重试！");
                }
                //校验主任务是否在数据加密阶段
                EduDataTask dataTask = eduDataTaskService.getById(taskDetail.getTaskId());
                if (!EduDataTaskTypeEnum.djm.getType().equals(dataTask.getStatus())){
                    throw new AppException(dataTask.getTaskName()+"不处于数据加密阶段，无法进行数据加密");
                }
                if (EduStatusTypeEnum.success.getType().equalsIgnoreCase(taskDetail.getEncryptStatus())){
                    throw new AppException(handleTable+"以完成加密，无需再次进行加密处理！");
                }
                //根据配置的表名来执行数据加密
                TableService tableService = TableServiceFactory.getTableService(handleTable);
                DataTaskDetailOptionVO optionVO = new DataTaskDetailOptionVO();
                optionVO.setYear(vo.getYear());
                optionVO.setTaskDetailId(vo.getTaskDetailId());
                //执行具体加密方法
                try {
                    tableService.dataEncryption(optionVO);
                }catch(AppException e){
                    throw new AppException(taskDetail.getHandleTable()+":"+e);
                } catch (Exception e) {
                    throw new RuntimeException(taskDetail.getHandleTable()+":"+e);
                }
                //检查加密任务是否已全部执行完毕
                this.checkEncryptionTask(taskDetail.getTaskId());
            } else {
                // 未获取到锁，表示已经有其他请求在处理
                throw new AppException(taskDetail.getHandleTable() +"正在进行数据加密，请稍后再试");
            }
        }catch (AppException e){
            throw new AppException(e.getMessage());
        } catch (Exception e) {
             throw  new RuntimeException(e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }


    @Override
    @OpApi(funcCode = "eduDataTaskDetail0009", title = "单业务数据解密到临时表", funcType = FuncTypeEnum.update)
    public void dataTaskDetailDecrypt(EduDataTaskDetailQueryVO vo) {
        if (ObjectUtils.isEmpty(vo.getYear())){
            throw new AppException("年份不能为空！");
        }
        if (ObjectUtils.isEmpty(vo.getTaskDetailId())){
            throw new AppException("任务详情id不能为空");
        }
        EduDataTaskDetail taskDetail = eduDataTaskDetailService.getById(vo.getTaskDetailId());
        if (ObjectUtils.isEmpty(taskDetail)) {
            throw new AppException("查询不到详细信息!");
        }
        //判断是否执行过数据迁移
        if (!EduStatusTypeEnum.success.getType().equalsIgnoreCase(taskDetail.getMigrationStatus())){
            throw new AppException(taskDetail.getHandleTable()+"未执行数据迁移，无需进行数据解密!");
        }
        String handleTable = taskDetail.getHandleTable();
        if (ObjectUtils.isEmpty(handleTable)){
            throw new AppException("任务配置的表名为空，请联系检查数据:"+taskDetail.getTaskDetailId());
        }
        RLock lock = redissonClient.getLock(EduCache.EDU_DATA_TASK_DETAIL +taskDetail.getHandleTable()+ vo.getTaskDetailId());
        try {
            boolean lockAcquired = lock.tryLock(1000, 200000, TimeUnit.MILLISECONDS); // 尝试获取锁
            if (lockAcquired) {
                //根据配置的表名来执行数据解密
                TableService tableService = TableServiceFactory.getTableService(handleTable);
                DataTaskDetailOptionVO optionVO = new DataTaskDetailOptionVO();
                optionVO.setYear(vo.getYear());
                optionVO.setTaskDetailId(vo.getTaskDetailId());
                //执行具体数据恢复方法
                tableService.dataDecrypt(optionVO);
            } else {
                // 未获取到锁，表示已经有其他请求在处理
                throw new AppException(taskDetail.getHandleTable() +"正在进行数据恢复，请稍后再试");
            }
        } catch (Exception e) {
            // 对于业务相关的异常，可以考虑捕获并抛出更具体的异常类型
            if(e instanceof AppException){
                throw (AppException)e;
            } else {
                // 在日志中记录异常详细信息，以方便问题追踪和定位
                // 日志框架需要根据实际情况引入
                throw new RuntimeException("数据解密过程中发生异常", e);
            }
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    @OpApi(funcCode = "eduDataTaskDetail0010", title = "单业务数据核销", funcType = FuncTypeEnum.other)
    public void dataTaskDetailClean(EduDataTaskDetailQueryVO vo) {
        if (ObjectUtils.isEmpty(vo.getYear())){
            throw new AppException("年份不能为空！");
        }
        if (ObjectUtils.isEmpty(vo.getTaskDetailId())){
            throw new AppException("任务详情id不能为空");
        }
        EduDataTaskDetail taskDetail = eduDataTaskDetailService.getById(vo.getTaskDetailId());
        if (ObjectUtils.isEmpty(taskDetail)) {
            throw new AppException("查询不到详细信息!");
        }
        RLock lock = redissonClient.getLock(EduCache.EDU_DATA_TASK_DETAIL + vo.getTaskDetailId());
        try {
            //查询是否获取到锁
            boolean cleanLock = lock.tryLock(3000, 20000, TimeUnit.MILLISECONDS);
            if (cleanLock) {
                //获取到锁
                String handleTable = taskDetail.getHandleTable();
                if (ObjectUtils.isEmpty(handleTable)){
                    throw new AppException("任务配置的表名为空，请联系检查数据:"+taskDetail.getTaskDetailId());
                }
                //校验单任务是否核销过
                if (EduStatusTypeEnum.success.getType().equalsIgnoreCase(taskDetail.getCleanStatus())){
                    throw new AppException("当前"+handleTable+"表清洗已完成，无需再次进行清洗");
                }
                TableService tableService = TableServiceFactory.getTableService(handleTable);
                DataTaskDetailOptionVO optionVO = new DataTaskDetailOptionVO();
                optionVO.setYear(vo.getYear());
                optionVO.setTaskDetailId(vo.getTaskDetailId());
                //调用空闲数据销毁
                Integer cleanCount = 0;
                try {
                    cleanCount = tableService.dataDestruction(optionVO);
                    taskDetail.setCleanStatus(EduStatusTypeEnum.success.getType());
                    taskDetail.setCleanRemarks("清洗成功！");
                    taskDetail.setCleanTime(new Date());
                    if (cleanCount != 0){
                        taskDetail.setCleanCount(cleanCount);
                    }
                    eduDataTaskDetailService.updateById(taskDetail);
                    //检查清洗任务是否全部执行完毕
                    this.checkCleanTask(taskDetail.getTaskId());
                } catch(AppException e){
                    throw new AppException(taskDetail.getHandleTable()+":"+e);
                } catch (Exception e) {
                    throw new RuntimeException(taskDetail.getHandleTable()+":"+e);
                }
            }else {
                throw new AppException(taskDetail.getHandleTable() +"正在进行数据清洗，请稍后再试");
            }
        }catch (AppException e){
            log.error(e.getMessage());
        }catch (Exception e){
            EduDataTaskDetail newTaskDetail = eduDataTaskDetailService.getById(vo.getTaskDetailId());
            if (!EduStatusTypeEnum.success.getType().equalsIgnoreCase(newTaskDetail.getCleanStatus())){
                //清洗失败，发生异常
                taskDetail.setCleanStatus(EduStatusTypeEnum.error.getType());
                String errorMessage = e.getMessage();
                if (errorMessage.length() > 200) {
                    errorMessage = errorMessage.substring(0, 200); // 截断到指定长度
                }
                taskDetail.setCleanRemarks(errorMessage);
                taskDetail.setCleanTime(new Date());
                eduDataTaskDetailService.updateById(taskDetail);
            }
            throw new RuntimeException(e);
        }finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 检查任务是否都清洗完成
     * @param taskId
     */
    private void checkCleanTask(String taskId) {
        QueryWrapper<EduDataTaskDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(EduDataTaskDetail::getTaskId,taskId);
        boolean checkFlag = true;
        List<EduDataTaskDetail> detailList = eduDataTaskDetailService.list(queryWrapper);
        for (EduDataTaskDetail taskDetail : detailList) {
            if (!EduStatusTypeEnum.success.getType().equalsIgnoreCase(taskDetail.getCleanStatus())){
                checkFlag = false;
                break;
            }
        }
        //所有子任务都迁移成功，修改主任务状态 修改为待确认状态
        if (checkFlag){
            EduDataTask dataTask = eduDataTaskService.getById(taskId);
            dataTask.setStatus(EduDataTaskTypeEnum.dqr.getType());
            dataTask.setErrorFlag(BoolEnum.FALSE.getType());
            dataTask.setErrorRemarks(null);
            eduDataTaskService.updateById(dataTask);
        }
    }

    /**
     * 检查加密状态
     * @param taskId
     */
    private void checkEncryptionTask(String taskId) {
        QueryWrapper<EduDataTaskDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(EduDataTaskDetail::getTaskId,taskId);
        boolean checkFlag = true;
        List<EduDataTaskDetail> detailList = eduDataTaskDetailService.list(queryWrapper);
        for (EduDataTaskDetail taskDetail : detailList) {
            if (!EduStatusTypeEnum.success.getType().equalsIgnoreCase(taskDetail.getEncryptStatus())){
                checkFlag = false;
                break;
            }
        }
        //所有子任务都迁移成功，修改主任务状态
        if (checkFlag){
            EduDataTask dataTask = eduDataTaskService.getById(taskId);
            dataTask.setStatus(EduDataTaskTypeEnum.dxh.getType());
            dataTask.setErrorFlag(BoolEnum.FALSE.getType());
            dataTask.setErrorRemarks(null);
            eduDataTaskService.updateById(dataTask);
        }
    }

    /**
     * 检查任务是否都加密完成
     * @param taskId
     */
    private void checkMigrationTask(String taskId) {
        QueryWrapper<EduDataTaskDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(EduDataTaskDetail::getTaskId,taskId);
        boolean checkFlag = true;
        List<EduDataTaskDetail> detailList = eduDataTaskDetailService.list(queryWrapper);
        for (EduDataTaskDetail taskDetail : detailList) {
            if (!EduStatusTypeEnum.success.getType().equalsIgnoreCase(taskDetail.getMigrationStatus())){
                checkFlag = false;
                break;
            }
        }

        //所有子任务都迁移成功，修改主任务状态
        if (checkFlag){
            EduDataTask dataTask = eduDataTaskService.getById(taskId);
            dataTask.setStatus(EduDataTaskTypeEnum.djm.getType());
            dataTask.setErrorFlag(BoolEnum.FALSE.getType());
            dataTask.setErrorRemarks(null);
            eduDataTaskService.updateById(dataTask);
        }

    }
}
